home *** CD-ROM | disk | FTP | other *** search
/ Graphics Plus / Graphics Plus.iso / libs / phigs / ptk.lha / ptk / source / library / cns.c next >
Encoding:
C/C++ Source or Header  |  1992-10-01  |  30.2 KB  |  1,172 lines

  1. /*----------------------------------------------------------------------------
  2.  
  3.  Module name: colour naming scheme.
  4.  
  5.  Author: W.T. Hewitt.
  6.  
  7.  Function: provides an English-based interface for defining colour values.
  8.  
  9.  Internal function list: ptk_huev, ptk_litv, ptk_satv, ptk_vsh, 
  10.  ptk_split, ptk_cpack, ptk_cunpack, ptk_cnp, ptk_rgbv.
  11.  
  12.  External function list: ptk_hsltorgb, ptk_rgbtohsl, ptk_hsvtorgb,
  13.  ptk_rgbtohsv, ptk_cnstorgb, ptk_setcnsdefaults, ptk_inqcnsdefaults.
  14.  
  15.  Hashtables used: "colourindex".
  16.  
  17.  Modification history: (Version), (Date), (Name), (Description).
  18.  
  19.  1.0, ?????, W.T. Hewitt, First version.
  20.  
  21.  2.0, 8th April 1991, J.G. Williams, Converted from FORTRAN to C.
  22.  
  23.  3.0, June 1992, G. Williams, Converted to ISO PHIGS C.
  24.  
  25. ----------------------------------------------------------------------------*/
  26.  
  27. #include <stdio.h>
  28. #include <math.h>
  29. #include <ctype.h>
  30. #include <phigs.h>
  31. #include "ptk.h"
  32.  
  33. /*--------------------------------------------------------------------------*/
  34.  
  35. #define ILOFF      0
  36. #define ILLEN      5
  37. #define ISOFF      5
  38. #define ISLEN      4
  39. #define IHOFF      9
  40. #define IHLEN      44
  41.  
  42. /*--------------------------------------------------------------------------*/
  43.  
  44. static char *colwrd[] = 
  45.      {
  46.         "VERY-DARK","DARK","MEDIUM","LIGHT","VERY-LIGHT",
  47.          "GREYISH","MODERATE","STRONG","VIVID",
  48.          "RED","ORANGISH-RED", "BROWNISH-RED","ORANGE-RED",
  49.          "RED-ORANGE","BROWN-RED","RED-BROWN", "REDDISH-ORANGE",
  50.         "REDDISH-BROWN","ORANGE","BROWN","YELLOWISH-ORANGE",
  51.          "YELLOWISH-BROWN","YELLOW-ORANGE","ORANGE-YELLOW", 
  52.          "YELLOW-BROWN","BROWN-YELLOW", "ORANGISH-YELLOW", 
  53.          "BROWNISH-YELLOW", "YELLOW",
  54.          "GREENISH-YELLOW","GREEN-YELLOW","YELLOW-GREEN",
  55.          "YELLOWISH-GREEN", "GREEN", "BLUISH-GREEN", "BLUE-GREEN",
  56.          "GREEN-BLUE","GREENISH-BLUE", "BLUE","PURPLISH-BLUE",
  57.          "PURPLE-BLUE","BLUE-PURPLE","BLUISH-PURPLE",
  58.         "PURPLE","REDDISH-PURPLE","RED-PURPLE","PURPLE-RED",
  59.          "PURPLISH-RED", "MAGENTA", "CYAN", "BLACK", "GREY", "WHITE" 
  60.      };
  61.     
  62. static Pfloat vsh[44][3] = 
  63.      {
  64.          1.0, 1.0, 0.0,  1.0, 1.0, 1.0,  0.8, 0.8, 1.0,  1.0, 1.0, 2.0,
  65.          1.0, 1.0, 2.0,  0.8, 0.8, 2.0,  0.8, 0.8, 2.0,  1.0, 1.0, 3.0,
  66.          0.8, 0.8, 3.0,  1.0, 1.0, 4.0,  0.8, 0.8, 4.0,  1.0, 1.0, 5.0,
  67.          0.8, 0.8, 5.0,  1.0, 1.0, 6.0,  1.0, 1.0, 6.0,  0.8, 0.8, 6.0,
  68.          0.8, 0.8, 6.0,  1.0, 1.0, 7.0,  0.8, 0.8, 7.0,  1.0, 1.0, 8.0,
  69.          1.0, 1.0, 10.0,  1.0, 1.0, 12.0,  1.0, 1.0, 12.0,  1.0, 1.0, 14.0,
  70.          1.0, 1.0, 16.0,  1.0, 1.0, 20.0,  1.0, 1.0, 24.0,  1.0, 1.0, 24.0,
  71.          1.0, 1.0, 28.0,  1.0, 1.0, 32.0,  1.0, 1.0, 34.0,  1.0, 1.0, 36.0,
  72.          1.0, 1.0, 36.0,  1.0, 1.0, 38.0,  1.0, 1.0, 40.0,  1.0, 1.0, 42.0,
  73.          1.0, 1.0, 44.0,  1.0, 1.0, 44.0,  1.0, 1.0, 46.0,  1.0, 1.0, 40.0, 
  74.         1.0, 1.0, 24.0,  0.0, 0.0, 0.0,   1.0, 0.0, 0.0,   1.0, 0.0, 0.0 
  75.      };
  76.  
  77. static char *shtwrd[] = 
  78.      { "L1","L2","L3","L4","L5","S1","S2","S3","S4",
  79.        "H/","H0","H1","H2","H3","H4","H5","H6","H7",
  80.        "H8","H9","H*","H:","H;","H<","H=","H>","H?",
  81.        "H@","HA","HB","HC","HD","HE","HF","HG","HI",
  82.        "HJ","HK","HL","HM","HN","HO","HP","HQ","HR",
  83.        "HS","HT","HU","HV","HW","HX","HY","HZ" 
  84.      };
  85.  
  86. static Pint deflight = 3;
  87. static Pint defsat = 8;
  88.  
  89. static char **rgbnames;
  90. static Prgb *rgbvalues;
  91. static Pint numrgbs = 0;
  92.     
  93. /*--------------------------------------------------------------------------*/
  94.  
  95. static Pint ptk_huev(C(char *) word, C(Phsv *) hsv) 
  96. PreANSI(char *word)
  97. PreANSI(Phsv *hsv)
  98. /*
  99. ** \parambegin
  100. ** \param{}{word}{hue name (shorthand version)}{IN}
  101. ** \param{}{hls}{HSV triplet}{IN}
  102. ** return value: 0 if HSV ok, -1 if not ok.
  103. ** \paramend
  104. ** \blurb{This function returns the HSV value for hue name
  105. ** \pardesc{word}.}
  106. */
  107. {    
  108.   Pint ii, jj;
  109.  
  110.   ii = instrlist(&shtwrd[IHOFF], IHLEN, word);
  111.  
  112.   if (ii >= 0) 
  113.   { 
  114.     hsv->hue = vsh[ii][2]/48.0;
  115.     hsv->satur = vsh[ii][1];
  116.     hsv->value = vsh[ii][0];
  117.     return 0;
  118.   }
  119.   else
  120.   {
  121.     /* call iferror(-1,'PTK_HUEV - invalid Hue name') */
  122.     return -1;
  123.   }
  124. }  /* ptk_huev */
  125.  
  126. /*--------------------------------------------------------------------------*/
  127.  
  128. static Pint ptk_litv(C(char *) word, C(Phsv *) hsv)
  129. PreANSI(char *word)
  130. PreANSI(Phsv *hsv)
  131. /*
  132. ** \parambegin
  133. ** \param{}{word}{lightness name (shorthand version)}{IN}
  134. ** \param{}{hls}{HSV value}{IN}
  135. ** return value: 0 if HSV ok, -1 if not ok.
  136. ** \paramend
  137. ** \blurb{This function returns the HSV value for lightness \pardesc{name}.}
  138. */
  139. {
  140.   Pint ii, jj;
  141.  
  142.   ii = instrlist(&shtwrd[ILOFF], ILLEN, word);
  143.  
  144.   if (ii >= 0)
  145.   { 
  146.     hsv->value = hsv->value * ((Pfloat)(ii + 1)/5.0);
  147.     return 0;
  148.   }
  149.   else
  150.   {      
  151.     /* call iferror(-1,'PTK_LITV - invalid lightness name') */
  152.     return -1;
  153.   }
  154. }
  155.      
  156. /*--------------------------------------------------------------------------*/
  157.  
  158. static Pint ptk_satv(C(char *) word, C(Phsv *) hsv)
  159. PreANSI(char *word)
  160. PreANSI(Phsv *hsv)
  161. /*
  162. ** \parambegin
  163. ** \param{}{word}{saturation name (shorthand version)}{IN}
  164. ** \param{}{hls}{HSV value}{IN}
  165. ** return value: 0 if HSV ok, -1 if not ok.
  166. ** \paramend
  167. ** \blurb{This function Return HSV value for saturation name.}
  168. */
  169. {    
  170.   Pint ii, jj;
  171.  
  172.   ii = instrlist(&shtwrd[ISOFF], ISLEN, word);
  173.  
  174.   if (ii >= 0) 
  175.   {
  176.     hsv->satur = hsv->satur * 0.25 * (Pfloat)(ii + 1);
  177.     return 0;
  178.   }
  179.   else
  180.   {
  181.     /* call iferror(-1,'PTK_SATV - invalid Saturation name') */
  182.     return -1;
  183.   }
  184. }
  185.  
  186. /*--------------------------------------------------------------------------*/
  187.  
  188. static Pint ptk_vsh(C(char *) word1, C(char *) word2, C(char *) word3, 
  189.                     C(Phsv *) hsv)
  190. PreANSI(char *word1)
  191. PreANSI(char *word2)
  192. PreANSI(char *word3)
  193. PreANSI(Phsv *hsv)
  194. /*
  195. ** \parambegin
  196. ** \param{}{word1}{lightness name}{IN}
  197. ** \param{}{word2}{saturation name}{IN}
  198. ** \param{}{word3}{hue name}{IN}
  199. ** \param{}{hls}{HSV triplet}{IN}
  200. ** return value: 0 if HSV ok, -1 if not ok.
  201. ** \paramend
  202. ** \blurb{This function Return HSV value for hue, saturation and lightness names.}
  203. */
  204. {    
  205.   Pint fvsh;
  206.  
  207.   fvsh = ptk_huev(word3, hsv);
  208.   if (fvsh == 0)
  209.   {
  210.     if ((strncmp(word3, "HX", 2) != 0) 
  211.          && (strncmp(word3, "HZ", 2) != 0))
  212.     {  
  213.       fvsh = ptk_litv(word1, hsv);
  214.       if ((fvsh == 0) && (strncmp(word2, "HY", 2) != 0)) 
  215.         fvsh = ptk_satv(word2, hsv);
  216.     }
  217.   }
  218.   return fvsh;
  219. }
  220.  
  221. /*--------------------------------------------------------------------------*/
  222.  
  223. static void ptk_split(C(char *) linein, C(char *) lineout, C(Pint *) iword)
  224. PreANSI(char *linein)
  225. PreANSI(char *lineout)
  226. PreANSI(Pint *iword)
  227. /*
  228. ** \parambegin
  229. ** \param{}{linein}{line to split}{IN}
  230. ** \param{}{lineout}{split line}{IN}
  231. ** \param{}{iword}{number of words in line}{IN}
  232. ** \paramend
  233. ** \blurb{This function Removes leadings spaces, collapses multiple spaces to single 
  234. ** spaces and counts the number of words.}
  235. */
  236. {    
  237.   Pint ii, jj, ll;
  238.   char lastchar;
  239.  
  240.   *iword = 0;
  241.  
  242.   jj = strlen(linein);
  243.  
  244.   if (jj == 0) 
  245.     return;
  246.  
  247.   *iword = 1;
  248.   ll = -1;
  249.   lastchar = ' ';
  250.   for (ii = 0; ii <= jj; ii++)
  251.   {      
  252.     if (linein[ii] != ' ') 
  253.     {
  254.       ll++;
  255.       lineout[ll] = linein[ii];
  256.       lastchar = lineout[ll];
  257.     }
  258.     else
  259.     if (lastchar != ' ') 
  260.     {
  261.       (*iword)++;
  262.       ll++;
  263.       lineout[ll] = ' ';
  264.       lastchar = ' ';
  265.     }
  266.   }
  267.   lineout[jj + 1] = '\0';
  268. }
  269.  
  270. /*--------------------------------------------------------------------------*/
  271.  
  272. static Pint ptk_cpack(C(char *) line, C(char *) pline)
  273. PreANSI(char *line)
  274. PreANSI(char *pline)
  275. /*
  276. ** \parambegin
  277. ** \param{}{line}{longhand colour description}{IN}
  278. ** \param{}{pline}{shorthand colour description}{IN}
  279. ** return value: 0 if ok, -1 if not ok.
  280. ** \paramend
  281. ** \blurb{This function Pack a colour description into 6 characters.}
  282. */
  283. {
  284.   Pint fcpk;
  285.   Pint r, g, b;
  286.     
  287.   fcpk = ptk_cnp(line, pline, colwrd, shtwrd, 0);
  288.   return fcpk;
  289. }
  290.  
  291. /*--------------------------------------------------------------------------*/
  292.  
  293. static Pint ptk_cnp(C(char *) line, C(char *) pline, C(char **) inwrd, 
  294.                     C(char **) otwrd)
  295. PreANSI(char *line)
  296. PreANSI(char *pline)
  297. PreANSI(char **inwrd)
  298. PreANSI(char **otwrd)
  299. /*
  300. ** \parambegin
  301. ** \param{}{line}{longhand colour description}{IN}
  302. ** \param{}{pline}{shorthand colour description}{IN}
  303. ** \param{}{inwrd}{pointer to longhand string list}{IN}
  304. ** \param{}{outwrd}{pointer to shorthand string list}{IN}
  305. ** \param{}{gap}{number of spaces between strings}{IN}
  306. ** \paramend
  307. ** \blurb{This function Translate words.
  308. ** Returns 0 if ok, -1 if not ok.}
  309. */
  310. {
  311.   char lline[60];
  312.   char word[20];
  313.   Pint ii, iword, iend, ist, jj, ll;
  314.   Pint fcnp;
  315.   char tempstr[255];
  316.  
  317.   /* Split etc into words */
  318.  
  319.   ptk_split(line, lline, &iword);
  320.  
  321.   strupper(lline);
  322.  
  323.   ll = 0;
  324.   ist = 0;
  325.   fcnp = 0;
  326.  
  327.   /* Copy words */
  328.  
  329.   for (ii = 0; ii < iword; ii++)
  330.   {    
  331.     iend = stringlength(&lline[ist]) + ist;
  332.     
  333.     strncpy(word, &lline[ist], iend - ist);
  334.     word[iend - ist] = '\0';
  335.  
  336.     strncpy(tempstr, word, (iend - ist + 1)); 
  337.  
  338.     jj = instrlist(inwrd, 53, tempstr);
  339.  
  340.     if (jj >= 0) 
  341.     {
  342.       strncpy(&pline[ll], otwrd[jj], 2);
  343.       ll = ll + 2;
  344.     }
  345.     else
  346.     {
  347.       strncpy(&pline[ll], word, (iend-ist));
  348.       ll = ll + iend - ist;
  349.       fcnp = -1;
  350.     }
  351.     ist = iend + 1;
  352.   }
  353.   pline[ll] = '\0';
  354.   return fcnp;
  355. }
  356.  
  357. /*--------------------------------------------------------------------------*/
  358.  
  359. static Pfloat ptk_rgbv(C(Pfloat) m1, C(Pfloat) m2, C(Pfloat) h)
  360. PreANSI(Pfloat m1)
  361. PreANSI(Pfloat m2)
  362. PreANSI(Pfloat h)
  363. /*
  364. ** \parambegin
  365. ** \param{}{m1, m2}{real numbers}{IN}
  366. ** \param{}{h}{hue value}{IN}
  367. ** \paramend
  368. ** \blurb{This function Return R, G or B value given 3 real numbers.
  369. ** Returns R, G, or B value.}
  370. */
  371. {
  372.   Pfloat const1,const2;
  373.   Pfloat frgbv;
  374.  
  375.   const1 = 1.0/6.0;
  376.   const2 = 2.0/3.0;
  377.  
  378.   if (h > 1.0) 
  379.     h = h - 1.0;
  380.   if (h < 0.0) 
  381.     h = h + 1.0;
  382.  
  383.   if (h < const1) 
  384.     frgbv = m1 + ((m2 - m1) * h * 6.0);
  385.   else
  386.   if (h < 0.5) 
  387.     frgbv = m2; 
  388.   else
  389.   if (h < const2)
  390.     frgbv = m1 + ((m2 - m1) * (const2 - h) * 6.0); 
  391.   else
  392.     frgbv = m1;
  393.  
  394.   return frgbv;
  395. }
  396.  
  397. /*--------------------------------------------------------------------------*/
  398.  
  399. static void ptk_realtocobundl(C(Pfloat *) reals, C(Prgb *) col,
  400.                               C(Pint) model)
  401. PreANSI(Pfloat reals[3])
  402. PreANSI(Prgb *col)
  403. PreANSI(Pint model)
  404. {
  405.   col->red = reals[0];
  406.   col->green = reals[1];
  407.   col->blue = reals[2];
  408. }
  409.  
  410. /*--------------------------------------------------------------------------*/
  411.  
  412. static void ptk_cobundltoreal(C(Pfloat *) reals, C(Prgb *) col,
  413.                               C(Pint) model)
  414. PreANSI(Pfloat reals[3])
  415. PreANSI(Prgb *col)
  416. PreANSI(Pint model)
  417. {
  418.   reals[0] = col->red;
  419.   reals[1] = col->green;
  420.   reals[2] = col->blue;
  421. }
  422.  
  423. /*--------------------------------------------------------------------------*/
  424.  
  425. static void convertcolourname(C(char *) colourname, C(Prgb *) rgb,
  426.                                  C(Pint *) err)
  427. PreANSI(char *colourname)
  428. PreANSI(Prgb *rgb)
  429. PreANSI(Pint *err)
  430. /*
  431. ** \parambegin
  432. ** \param{}{colourname}{colour description}{IN}
  433. ** \param{}{rgb}{RGB triplet}{IN}
  434. ** \paramend
  435. ** \blurb{This function Converts longhand colour description to RGB->
  436. ** Returns TRUE if ok, FALSE if not ok.}
  437. */
  438. {
  439.   char lpack[7];
  440.   Phsv hsv;
  441.   Pint ii, iword, r, g, b;
  442.   char word[3][3];
  443.   Pint fcns;
  444.   Pfloat argb[3];
  445.  
  446.   *err = 0;
  447.   /* pack into internal format */
  448.   fcns = ptk_cpack(colourname, lpack);
  449.   if (fcns == 0)
  450.   {
  451.     iword = stringlength(lpack);
  452.     iword = (Pint)iword/2;
  453.     if (iword == 0)
  454.     {
  455.       /* blank line */
  456.       *err = 1;
  457.       return;
  458.     }
  459.   
  460.     /* Iword should be 1,2 or 3 */
  461.     /*
  462.     ** Iword = 1 => HUE only
  463.     ** Iword = 2 => Lightness hue or saturation hue
  464.     ** Iword = 3 => Lightness sat hue or sat light hue
  465.     ** (HUE is ALWAYS last)
  466.     */
  467.   
  468.     /* extract separate words */
  469.   
  470.     for (ii = 0; ii < iword; ii++)
  471.     { 
  472.       strncpy(word[ii], &lpack[2 * ii], 2);
  473.       word[ii][2] = '\0';
  474.     }
  475.   
  476.     /*
  477.     ** light = 'L4'
  478.     ** vivid = 'S4'
  479.     */
  480.   
  481.     if (iword == 1)
  482.       fcns = ptk_vsh(shtwrd[deflight], shtwrd[defsat], word[0], &hsv);
  483.     else
  484.     if (iword == 2) 
  485.     {
  486.       if (ptk_litv(word[0], &hsv) == 0) 
  487.         fcns = ptk_vsh(word[0], shtwrd[defsat], word[1], &hsv);
  488.       else
  489.         fcns = ptk_vsh(shtwrd[deflight], word[0], word[1], &hsv); 
  490.     }
  491.     else
  492.     {
  493.       if (ptk_litv(word[0], &hsv) == 0) 
  494.         fcns = ptk_vsh(word[0], word[1], word[2], &hsv);
  495.       else
  496.         fcns = ptk_vsh(word[1], word[0], word[2], &hsv);
  497.     }  
  498.   }
  499.  
  500.   if (fcns == 0)
  501.   {
  502.     ptk_hsvtorgb(&hsv, rgb);
  503.     return;
  504.   }
  505.   else
  506.   {
  507.     /* try rgb colour names */
  508.     ii = instrlist(rgbnames, numrgbs, colourname);
  509.     if (ii >= 0)
  510.     {
  511.       *rgb = rgbvalues[ii];
  512.       *err = 2;    
  513.       return;
  514.     }
  515.   }
  516.   /* failed to convert colour, using white */
  517.   argb[0] = 1.0;
  518.   argb[1] = 1.0;
  519.   argb[2] = 1.0;
  520.   ptk_realtocobundl(argb, rgb, 1);
  521.   *err = 3;
  522. }  /* convertcolourname */
  523.  
  524. /*--------------------------------------------------------------------------*/
  525.  
  526. static void setcolourrep(C(Pint) wsid, C(char *) colourname, 
  527.                          C(Pint *) cindex)
  528. PreANSI(Pint wsid)
  529. PreANSI(char *colourname)
  530. PreANSI(Pint *cindex)
  531. {
  532.   Pcolr_rep rgb;
  533.   Pint err;
  534.  
  535.   convertcolourname(colourname, &rgb, &err);
  536.   if ((err == 0) || (err == 2))
  537.   {
  538.     *cindex = ptk_stringtoint("colourindex", colourname);
  539.     pset_colr_rep(wsid, *cindex, &rgb);
  540.   }
  541.   else
  542.     *cindex = -1;
  543. }  /* setcolourrep */
  544.  
  545. /*--------------------------------------------------------------------------*/
  546.  
  547. /*function:external*/
  548. extern void ptk_hsltorgb(C(Phls *) hsl, C(Prgb *) rgb)
  549. PreANSI(Phls *hsl)
  550. PreANSI(Prgb *rgb)
  551. /*
  552. ** \parambegin
  553. ** \param{Phls *}{hsl}{HSL triplet}{IN}
  554. ** \param{Prgb *}{rgb}{RGB triplet}{IN}
  555. ** \paramend
  556. ** \blurb{This function converts from the HSL double-ended hexcone 
  557. ** model to the 
  558. ** RGB model. Given HSL, the equivalent RGB parameters are computed.
  559. ** All parameters are assumed to be in the range 0.0 to 1.0. The
  560. ** algorithm is adapted from~\cite{foley:fic}.}
  561. */
  562. {
  563.   Pfloat value, m1, m2;
  564.   Pfloat ahsl[3], argb[3];
  565.  
  566.   value = 1.0/3.0;
  567.  
  568.   ptk_cobundltoreal(ahsl, hsl, 2);
  569.   if (ahsl[2] <= 0.5) 
  570.     m2 = ahsl[2] * (1.0 + ahsl[1]);
  571.   else
  572.     m2 = ahsl[2] + ahsl[1] - (ahsl[2] * ahsl[1]);
  573.  
  574.   m1 = 2.0 * ahsl[2] - m2;
  575.   if (ahsl[1] == 0.0) 
  576.   {
  577.     argb[0] = ahsl[2];
  578.     argb[1] = ahsl[2];
  579.     argb[2] = ahsl[2];
  580.   }
  581.   else
  582.   {  
  583.     argb[0] = ptk_rgbv(m1, m2, ahsl[0] + value);
  584.     argb[1] = ptk_rgbv(m1, m2, ahsl[0]);
  585.     argb[2] = ptk_rgbv(m1, m2, ahsl[0] - value);
  586.   }
  587.   ptk_realtocobundl(argb, rgb, 1);
  588. }  /* ptk_hsltorgb */
  589.  
  590. /*--------------------------------------------------------------------------*/
  591.  
  592. /*function:external*/
  593. extern void ptk_rgbtohsl(C(Prgb *) rgb, C(Phls *) hsl)
  594. PreANSI(Prgb *rgb)
  595. PreANSI(Phls *hsl)
  596. /*
  597. ** \parambegin
  598. ** \param{Prgb *}{rgb}{RGB triplet}{IN}
  599. ** \param{Phls *}{hsl}{HSL triplet}{IN}
  600. ** \paramend
  601. ** \blurb{This function converts an RGB triplet to a HSL triplet.
  602. ** The
  603. ** algorithm is adapted from~\cite{watt:fotdcg}.}
  604. */
  605. {
  606.   Pfloat maxval, minval, diff, rdist, gdist, bdist;
  607.   Pfloat ahsl[3], argb[3];
  608.  
  609.   ptk_cobundltoreal(argb, rgb, 1);
  610.   maxval = PTKMAX(argb[0], argb[1]);
  611.   maxval = PTKMAX(maxval, argb[2]);
  612.   minval = PTKMIN(argb[0], argb[1]);
  613.   minval = PTKMIN(minval, argb[2]);
  614.   diff = maxval - minval;
  615.   ahsl[2] = (maxval + minval) / 2.0;
  616.   if (abs(diff) < 0.00001)
  617.   {  
  618.     ahsl[1] = 0.0;
  619.     ahsl[0] = 0.0; /* undefined */
  620.   }
  621.   else
  622.   {
  623.     if (ahsl[2] <= 0.5)
  624.       ahsl[1] = diff / (maxval + minval);
  625.     else
  626.       ahsl[1] = diff / (2.0 - maxval - minval);
  627.     rdist = (maxval - argb[0])/diff;
  628.     gdist = (maxval - argb[1])/diff;
  629.     bdist = (maxval - argb[2])/diff;
  630.     if (argb[0] == maxval)
  631.       ahsl[0] = bdist - gdist;
  632.     else
  633.     if (argb[1] == maxval)
  634.       ahsl[0] = 2.0 + rdist - bdist;
  635.     else
  636.     if (argb[2] == maxval)
  637.       ahsl[0] = 4.0 + gdist - rdist;
  638.     ahsl[0] *= 60.0;
  639.     if (ahsl[0] < 0.0)
  640.       ahsl[0] += 360.0;
  641.   }  
  642.   ptk_realtocobundl(ahsl, hsl, 2);
  643. }  /* ptk_rgbtohsl */
  644.  
  645. /*--------------------------------------------------------------------------*/
  646.  
  647. /*function:external*/
  648. extern void ptk_hsvtorgb(C(Phsv *) hsv, C(Prgb *) rgb)
  649. PreANSI(Phsv *hsv)
  650. PreANSI(Prgb *rgb)
  651. /*
  652. ** \parambegin
  653. ** \param{Phsv *}{hsv}{HSV triplet}{IN}
  654. ** \param{Prgb *}{rgb}{RGB triplet}{IN}
  655. ** \paramend
  656. ** \blurb{This function converts a HSV triplet to a RGB triplet. 
  657. ** The
  658. ** algorithm is adapted from~\cite{watt:fotdcg}.}
  659. */
  660. {
  661.   Pfloat f, p, q, t;
  662.   Pint i;
  663.   Pfloat ahsv[3], argb[3];
  664.  
  665.   ptk_cobundltoreal(ahsv, hsv, 3);
  666.   if (ahsv[1] == 0.0)
  667.   {
  668.     argb[0] = ahsv[2];
  669.     argb[1] = ahsv[2];
  670.     argb[2] = ahsv[2];
  671.   }
  672.   else
  673.   {
  674.     if (ahsv[0] == 1.0)
  675.       ahsv[0] = 0.0;
  676.     ahsv[0] *= 6.0;
  677.     i = floor(ahsv[0]);
  678.     f = ahsv[0] - (Pfloat)i;
  679.     p = ahsv[2] * (1.0 - ahsv[1]);
  680.     q = ahsv[2] * (1.0 - (ahsv[1] * f));
  681.     t = ahsv[2] * (1.0 - (ahsv[1] * (1.0 - f)));
  682.     switch (i) 
  683.     {
  684.     case 0: argb[0] = ahsv[2];
  685.             argb[1] = t;
  686.             argb[2] = p;
  687.             break;
  688.     case 1: argb[0] = q;
  689.             argb[1] = ahsv[2];
  690.             argb[2] = p;
  691.             break;
  692.     case 2: argb[0] = p;
  693.             argb[1] = ahsv[2];
  694.             argb[2] = t;
  695.             break;
  696.     case 3: argb[0] = p;
  697.             argb[1] = q;
  698.             argb[2] = ahsv[2];
  699.             break;
  700.     case 4: argb[0] = t;
  701.             argb[1] = p;
  702.             argb[2] = ahsv[2];
  703.             break;
  704.     case 5: argb[0] = ahsv[2];
  705.             argb[1] = p;
  706.             argb[2] = q;
  707.             break;
  708.     }
  709.   }
  710.   ptk_realtocobundl(argb, rgb, 1);
  711. }  /* ptk_hsvtorgb */
  712.  
  713. /*--------------------------------------------------------------------------*/
  714.  
  715. /*function:external*/
  716. extern void ptk_rgbtohsv(C(Prgb *) rgb, C(Phsv *) hsv)
  717. PreANSI(Prgb *rgb)
  718. PreANSI(Phsv *hsv)
  719. /*
  720. ** \parambegin
  721. ** \param{Prgb *}{rgb}{RGB triplet}{IN}
  722. ** \param{Phsv *}{hsv}{HSV triplet}{IN}
  723. ** \paramend
  724. ** \blurb{This function converts an RGB value to a HSV value.
  725. ** The
  726. ** algorithm is adapted from~\cite{watt:fotdcg}.}
  727. */
  728. {
  729.   Pfloat maxval, minval, diff, rdist, gdist, bdist;
  730.   Pfloat ahsv[3], argb[3];
  731.  
  732.   ptk_cobundltoreal(argb, rgb, 1);
  733.   maxval = PTKMAX(argb[0], argb[1]);
  734.   maxval = PTKMAX(maxval, argb[2]);
  735.   minval = PTKMIN(argb[0], argb[1]);
  736.   minval = PTKMIN(minval, argb[2]);
  737.   diff = maxval - minval;
  738.   ahsv[2] = maxval;
  739.   if (maxval != 0.0)
  740.     ahsv[1] = diff/maxval;
  741.   else
  742.     ahsv[1] = 0.0;
  743.   if (ahsv[1] == 0.0)
  744.     ahsv[0] = 0.0; /* undefined */
  745.   else
  746.   {
  747.     rdist = (maxval - argb[0])/diff;
  748.     gdist = (maxval - argb[1])/diff;
  749.     bdist = (maxval - argb[2])/diff;
  750.     if (argb[0] == maxval)
  751.       ahsv[0] = bdist - gdist;
  752.     else
  753.     if (argb[1] == maxval)
  754.       ahsv[0] = 2.0 + rdist - bdist;
  755.     else
  756.     if (argb[2] == maxval)
  757.       ahsv[0] = 4.0 + gdist - rdist;
  758.     ahsv[0] *= 60.0;
  759.     if (ahsv[0] < 0.0)
  760.       ahsv[0] += 360.0;
  761.   }
  762.   ptk_realtocobundl(ahsv, hsv, 3);
  763. }  /* ptk_rgbtohsv */
  764.  
  765. /*--------------------------------------------------------------------------*/
  766.  
  767. /*function:external*/
  768. extern ptkboolean ptk_cnstorgb(C(char *) colourname, C(Prgb *) rgb)
  769. PreANSI(char *colourname)
  770. PreANSI(Prgb *rgb)
  771. /*
  772. ** \parambegin
  773. ** \param{char *}{colourname}{colour description}{IN}
  774. ** \param{Prgb *}{rgb}{RGB triplet}{IN}
  775. ** \paramend
  776. ** \blurb{This function converts a CNS colour name to the equivalent
  777. **  RGB value, returning TRUE if the conversion was successful,
  778. ** and FALSE if not.}
  779. */
  780. {
  781.   Pint err;
  782.  
  783.   convertcolourname(colourname, rgb, &err);
  784.   if ((err == 0) || (err == 2))
  785.     return TRUE;
  786.   else
  787.   {
  788.     return FALSE;
  789.   }
  790. }  /* ptk_cnstorgb */
  791.  
  792. /*--------------------------------------------------------------------------*/
  793.  
  794. /*function:external*/
  795. extern ptkboolean ptk_cnstohsl(C(char *) colourname, C(Phls *) hsl)
  796. PreANSI(char *colourname)
  797. PreANSI(Phls *hsl)
  798. /*
  799. ** \parambegin
  800. ** \param{char *}{colourname}{colour description}{IN}
  801. ** \param{Phls *}{hsl}{HSL triplet}{IN}
  802. ** \paramend
  803. ** \blurb{This function converts a CNS colour name to the equivalent
  804. **  HSL value, returning TRUE if the conversion was successful,
  805. ** and FALSE if not.}
  806. */
  807. {
  808.   Prgb rgb;
  809.  
  810.   if (ptk_cnstorgb(colourname, &rgb))
  811.   {
  812.     ptk_rgbtohsl(&rgb, hsl);
  813.     return TRUE;
  814.   }
  815.   else
  816.     return FALSE;
  817. }  /* ptk_cnstohsl */
  818.  
  819. /*--------------------------------------------------------------------------*/
  820.  
  821. /*function:external*/
  822. extern ptkboolean ptk_cnstohsv(C(char *) colourname, C(Phsv *) hsv)
  823. PreANSI(char *colourname)
  824. PreANSI(Phsv *hsv)
  825. /*
  826. ** \parambegin
  827. ** \param{char *}{colourname}{colour description}{IN}
  828. ** \param{Phsv *}{hsv}{HSV triplet}{IN}
  829. ** \paramend
  830. ** \blurb{This function Converts colour name to HSV.
  831. ** Returns TRUE if ok, FALSE if not ok.}
  832. */
  833. {
  834.   Prgb rgb;
  835.  
  836.   if (ptk_cnstorgb(colourname, &rgb))
  837.   {
  838.     ptk_rgbtohsv(&rgb, hsv);
  839.     return TRUE;
  840.   }
  841.   else
  842.     return FALSE;
  843. }  /* ptk_cnstohsv */
  844.  
  845. /*--------------------------------------------------------------------------*/
  846.  
  847. /*function:external*/
  848. extern void ptk_setcnsdefaults(C(ptkelightness) lightness, 
  849.                                C(ptkesaturation) saturation)
  850. PreANSI(ptkelightness lightness)
  851. PreANSI(ptkesaturation saturation)
  852. /*
  853. ** \parambegin
  854. ** \param{ptkelightness}{lightness}{default lightness for colours}{IN}
  855. ** \param{ptkesaturation}{saturation}{default saturation for colours}{IN}
  856. ** \paramend
  857. ** \blurb{This function sets default values for lightness and
  858. **  saturation for the  Colour Naming
  859. ** Scheme. If lightness or saturation is missing when a 
  860. ** colour name is subsequently specified, the
  861. ** default is used.}
  862. */
  863. {
  864.   if ((lightness >= 0) && (lightness <= 4))
  865.     deflight = lightness;
  866.   if ((saturation >= 0) && (saturation <= 3))
  867.     defsat = saturation + 5;
  868. }  /* ptk_setcnsdefaults */
  869.  
  870. /*--------------------------------------------------------------------------*/
  871.  
  872. /*function:external*/
  873. extern void ptk_inqcnsdefaults(C(ptkelightness *) lightness, 
  874.                                C(ptkesaturation *) saturation)
  875. PreANSI(ptkelightness *lightness)
  876. PreANSI(ptkesaturation *saturation)
  877. /*
  878. ** \parambegin
  879. ** \param{ptkelightness *}{lightness}{default lightness for colours}{OUT}
  880. ** \param{ptkesaturation *}{saturation}{default saturation for colours}{OUT}
  881. ** \paramend
  882. ** \blurb{This function inquires the
  883. **  default values of lightness and saturation used in the  Colour
  884. ** Naming Scheme.}
  885. */
  886. {
  887.   *lightness = deflight;
  888.   *saturation = defsat - 5;
  889. }  /* ptk_inqcnsdefaults */
  890.  
  891. /*--------------------------------------------------------------------------*/
  892.  
  893. /*function:external*/
  894. extern void ptk_setupcolourtable(C(Pint) wsid, C(Pint) num,
  895.                                  C(char **) colournames)
  896. PreANSI(Pint wsid)
  897. PreANSI(Pint num)
  898. PreANSI(char **colournames)
  899. /*
  900. ** \parambegin
  901. ** \param{Pint}{wsid}{workstation identifier}{IN}
  902. ** \param{Pint}{num}{number of colour names}{IN}
  903. ** \param{char **}{colournames}{list of colour names}{IN}
  904. ** \paramend
  905. ** \blurb{This function sets colour representations in 
  906. ** the colour table of workstation \pardesc{wsid},
  907. **  using the list of colour names \pardesc{colournames}. 
  908. ** The hashstrings table
  909. ** {\tt "colourindex"} is used to derive the index to the colour table.}
  910. */
  911. {
  912.   Pint i;
  913.   Pcolr_rep rep;
  914.  
  915.   for (i = 0; i < num; i++)
  916.   {
  917.     if (ptk_cnstorgb(colournames[i], &rep.rgb))
  918.       pset_colr_rep(wsid, ptk_stringtoint("colourindex", colournames[i]), 
  919.                     &rep);
  920.   }
  921. }  /* ptk_setupcolourtable */
  922.  
  923. /*--------------------------------------------------------------------------*/
  924.  
  925. /*function:external*/
  926. extern void ptk_setcolourrep(C(Pint) wsid, C(char *) colourname)
  927. PreANSI(Pint wsid)
  928. PreANSI(char *colourname)
  929. /*
  930. ** \parambegin
  931. ** \param{Pint}{wsid}{workstation identifier}{IN}
  932. ** \param{char *}{colourname}{colour name}{IN}
  933. ** \paramend
  934. ** \blurb{This function sets colour representations in 
  935. ** the colour table of workstation \pardesc{wsid},
  936. **  using the colour name \pardesc{colourname}. 
  937. ** The hashstrings table
  938. ** {\tt "colourindex"} is used to derive the index to the colour table.}
  939. */
  940. {
  941.   Pcolr_rep rep;
  942.  
  943.   if (ptk_cnstorgb(colourname, &rep.rgb))
  944.     pset_colr_rep(wsid, ptk_stringtoint("colourindex", colourname), &rep);
  945. }  /* ptk_setcolourrep */
  946.  
  947. /*--------------------------------------------------------------------------*/
  948.  
  949. /*function:external*/
  950. extern void ptk_setrgbcolourname(C(char *) colourname, C(Prgb *) rgb)
  951. PreANSI(char *colourname)
  952. PreANSI(Prgb *rgb)
  953. /*
  954. ** \parambegin
  955. ** \param{char *}{colourname}{colour name}{IN}
  956. ** \param{Prgb *}{rgb}{RGB colour value}{IN}
  957. ** \paramend
  958. ** \blurb{This function sets a colour representation in 
  959. ** CNS using the colour name and
  960. ** RGB value. The colour name must be different to the names provided by
  961. ** the CNS. This function enables additional names for colours to
  962. ** be specified in addition to those provided by CNS.}
  963. */
  964. {
  965.   Pint err, ii;
  966.   Prgb temp;
  967.  
  968.   convertcolourname(colourname, &temp, &err);
  969.   switch (err)
  970.   {
  971.     case 0: /* colourname is part of the colour naming scheme */
  972.       fprintf(stderr, "ptk_setrgbcolourname: sorry, colourname \"%s\" is part of the colour naming scheme\n", colourname);
  973.       break;
  974.  
  975.     case 1: /* blank line */
  976.       fprintf(stderr, "ptk_setrgbcolourname: sorry, colourname \"%s\" is invalid\n", colourname);
  977.       break;
  978.  
  979.     case 2: /* already defined rgb name */
  980.       ii = instrlist(rgbnames, numrgbs, colourname);
  981.       rgbvalues[ii] = *rgb;
  982.       break;
  983.  
  984.     case 3: /* name not rgb or cns */
  985.       numrgbs++;
  986.       if (numrgbs == 1)
  987.       {
  988.         rgbnames = (char **)calloc(1, sizeof(char *));
  989.         rgbvalues = (Prgb *)calloc(1, sizeof(Prgb));
  990.       }
  991.       else
  992.       {
  993.         rgbnames = (char **)realloc(rgbnames, numrgbs * sizeof(char *));
  994.         rgbvalues = (Prgb *)realloc(rgbvalues, numrgbs * sizeof(Prgb));
  995.       }
  996.       rgbnames[numrgbs - 1] = (char *)malloc(strlen(colourname) + 1);
  997.       strcpy(rgbnames[numrgbs - 1], colourname);
  998.       rgbvalues[numrgbs - 1] = *rgb;
  999.       break;
  1000.   }
  1001. }  /* ptk_setrgbcolourname */
  1002.  
  1003. /*--------------------------------------------------------------------------*/
  1004.  
  1005. /*function:external*/
  1006. extern void ptk_setbackgroundcolourind(C(Pint) wsid, C(Pint) index)
  1007. PreANSI(Pint wsid)
  1008. PreANSI(Pint index)
  1009. /*
  1010. ** \parambegin
  1011. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1012. ** \param{Pint}{index}{colour index}{IN}
  1013. ** \paramend
  1014. ** \blurb{This function sets the colour representation of the
  1015. **  zeroth entry in the
  1016. ** colour table of workstation \pardesc{wsid}, to be same as the
  1017. **  entry \pardesc{index} in the colour table.}
  1018. */
  1019. {
  1020.   Pcolr_rep colour;
  1021.   Pint err;
  1022.  
  1023.   pinq_colr_rep(wsid, index, PINQ_REALIZED, &err, &colour);  
  1024.   if (err == 0)
  1025.     pset_colr_rep(wsid, 0, &colour);
  1026. }  /* ptk_setbackgroundcolourind */
  1027.  
  1028. /*--------------------------------------------------------------------------*/
  1029.  
  1030. /*function:external*/
  1031. extern void ptk_setbackgroundcolour(C(Pint) wsid, C(char *) colourname)
  1032. PreANSI(Pint wsid)
  1033. PreANSI(char *colourname)
  1034. /*
  1035. ** \parambegin
  1036. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1037. ** \param{char *}{colourname}{colour name}{IN}
  1038. ** \paramend
  1039. ** \blurb{This function sets the colour representation of the
  1040. **  zeroth entry in the
  1041. ** colour table of workstation \pardesc{wsid}, to be that
  1042. ** specified by \pardesc{colourname} in the CNS.}
  1043. */
  1044. {
  1045.   Pint err;
  1046.   Pcolr_rep rep;
  1047.  
  1048.   convertcolourname(colourname, &rep.rgb, &err);
  1049.   if ((err == 0) || (err == 2))
  1050.     pset_colr_rep(wsid, 0, &rep);
  1051. }  /* ptk_setbackgroundcolour */
  1052.  
  1053. /*--------------------------------------------------------------------------*/
  1054.  
  1055. /*function:external*/
  1056. extern void ptk_setlinecolour(C(Pint) wsid, C(char *) colourname)
  1057. PreANSI(Pint wsid)
  1058. PreANSI(char *colourname)
  1059. /*
  1060. ** \parambegin
  1061. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1062. ** \param{char *}{colourname}{colour name}{IN}
  1063. ** \paramend
  1064. ** \blurb{This function sets the polyline colour index to be that specified by the given
  1065. ** colour name in the {\tt "colourindex"} hashtable. The colour representation
  1066. ** is set in the workstation colour table if necessary.}
  1067. */
  1068. {
  1069.   Pint cindex;
  1070.  
  1071.   setcolourrep(wsid, colourname, &cindex);
  1072.   if (cindex != -1)
  1073.     pset_line_colr_ind(cindex);
  1074. }  /* ptk_setlinecolour */
  1075.  
  1076. /*--------------------------------------------------------------------------*/
  1077.  
  1078. /*function:external*/
  1079. extern void ptk_setmarkercolour(C(Pint) wsid, C(char *) colourname)
  1080. PreANSI(Pint wsid)
  1081. PreANSI(char *colourname)
  1082. /*
  1083. ** \parambegin
  1084. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1085. ** \param{char *}{colourname}{colour name}{IN}
  1086. ** \paramend
  1087. ** \blurb{This function sets the polymarker colour index to be that specified by the given
  1088. ** colour name in the {\tt "colourindex"} hashtable. The colour representation
  1089. ** is set in the workstation colour table if necessary.}
  1090. */
  1091. {
  1092.   Pint cindex;
  1093.  
  1094.   setcolourrep(wsid, colourname, &cindex);
  1095.   if (cindex != -1)
  1096.     pset_marker_colr_ind(cindex);
  1097. }  /* ptk_setmarkercolour */
  1098.  
  1099. /*--------------------------------------------------------------------------*/
  1100.  
  1101. /*function:external*/
  1102. extern void ptk_setintcolour(C(Pint) wsid, C(char *) colourname)
  1103. PreANSI(Pint wsid)
  1104. PreANSI(char *colourname)
  1105. /*
  1106. ** \parambegin
  1107. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1108. ** \param{char *}{colourname}{colour name}{IN}
  1109. ** \paramend
  1110. ** \blurb{This function sets the interior colour index to be that specified by the given
  1111. ** colour name in the {\tt "colourindex"} hashtable. The colour representation
  1112. ** is set in the workstation colour table if necessary.}
  1113. */
  1114. {
  1115.   Pint cindex;
  1116.  
  1117.   setcolourrep(wsid, colourname, &cindex);
  1118.   if (cindex != -1)
  1119.     pset_int_colr_ind(cindex);
  1120. }  /* ptk_setintcolour */
  1121.  
  1122. /*--------------------------------------------------------------------------*/
  1123.  
  1124. /*function:external*/
  1125. extern void ptk_setedgecolour(C(Pint) wsid, C(char *) colourname)
  1126. PreANSI(Pint wsid)
  1127. PreANSI(char *colourname)
  1128. /*
  1129. ** \parambegin
  1130. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1131. ** \param{char *}{colourname}{colour name}{IN}
  1132. ** \paramend
  1133. ** \blurb{This function sets the edge colour index to be that specified by the given
  1134. ** colour name in the {\tt "colourindex"} hashtable. The colour representation
  1135. ** is set in the workstation colour table if necessary.}
  1136. */
  1137. {
  1138.   Pint cindex;
  1139.  
  1140.   setcolourrep(wsid, colourname, &cindex);
  1141.   if (cindex != -1)
  1142.     pset_edge_colr_ind(cindex);
  1143. }  /* ptk_setedgecolour */
  1144.  
  1145. /*--------------------------------------------------------------------------*/
  1146.  
  1147. /*function:external*/
  1148. extern void ptk_settextcolour(C(Pint) wsid, C(char *) colourname)
  1149. PreANSI(Pint wsid)
  1150. PreANSI(char *colourname)
  1151. /*
  1152. ** \parambegin
  1153. ** \param{Pint}{wsid}{workstation identifier}{IN}
  1154. ** \param{char *}{colourname}{colour name}{IN}
  1155. ** \param{Pint}{index}{colour index}{IN}
  1156. ** \paramend
  1157. ** \blurb{This function sets the text colour index to be that specified by the given
  1158. ** colour name in the {\tt "colourindex"} hashtable. The colour representation
  1159. ** is set in the workstation colour table if necessary.}
  1160. */
  1161. {
  1162.   Pint cindex;
  1163.  
  1164.   setcolourrep(wsid, colourname, &cindex);
  1165.   if (cindex != -1)
  1166.     pset_text_colr_ind(cindex);
  1167. }  /* ptk_settextcolour */
  1168.  
  1169. /*--------------------------------------------------------------------------*/
  1170.  
  1171. /* end of cns.c */
  1172.